package com.ruoyi.common.utils.date;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;

/**
 * @author xumh
 * @title: CalendarMeasureUtil
 * @projectName ruoyi
 * @description: TODO
 * @date 2024/12/1216:10
 */
public class CalendarMeasureUtil {
    public static String ZONE_GMT = "GMT+8:00";

    public CalendarMeasureUtil() {
    }

    public static CalendarMeasureUtil.Thisday thisday() {
        CalendarMeasureUtil.Thisday thisday = new CalendarMeasureUtil.Thisday();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        thisday.setYear(calendar.get(1));
        int month = calendar.get(2) + 1;
        thisday.setMonth(month);
        thisday.setDay(calendar.get(5));
        Integer quarter = 0;
        if (month >= 1 && month <= 3) {
            quarter = 1;
        } else if (month >= 4 && month <= 6) {
            quarter = 2;
        } else if (month >= 7 && month <= 9) {
            quarter = 3;
        } else if (month >= 10 && month <= 12) {
            quarter = 4;
        }

        thisday.setQuarter(quarter);
        return thisday;
    }

    public static Long getDailyStartTime(Long timeStamp, String timeZone) {
        if (timeZone == null) {
            timeZone = ZONE_GMT;
        }

        Calendar calendar = Calendar.getInstance();
        calendar.setTimeZone(TimeZone.getTimeZone(timeZone));
        calendar.setTimeInMillis(timeStamp);
        calendar.set(11, 0);
        calendar.set(13, 0);
        calendar.set(12, 0);
        calendar.set(14, 0);
        return calendar.getTimeInMillis();
    }

    public static Long getDailyEndTime(Long timeStamp, String timeZone) {
        if (timeZone == null) {
            timeZone = ZONE_GMT;
        }

        Calendar calendar = Calendar.getInstance();
        calendar.setTimeZone(TimeZone.getTimeZone(timeZone));
        calendar.setTimeInMillis(timeStamp);
        calendar.set(11, 23);
        calendar.set(12, 59);
        calendar.set(13, 59);
        calendar.set(14, 0);
        return calendar.getTimeInMillis();
    }

    public static Long getWeekStartTime(Long timeStamp, String timeZone) {
        if (timeZone == null) {
            timeZone = ZONE_GMT;
        }

        Calendar calendar = Calendar.getInstance();
        calendar.setTimeZone(TimeZone.getTimeZone(timeZone));
        calendar.setTimeInMillis(timeStamp);
        calendar.setFirstDayOfWeek(2);
        calendar.set(7, calendar.getFirstDayOfWeek());
        calendar.set(11, 0);
        calendar.set(13, 0);
        calendar.set(12, 0);
        calendar.set(14, 0);
        return calendar.getTimeInMillis();
    }

    public static Long getWeekEndTime(Long timeStamp, String timeZone) {
        if (timeZone == null) {
            timeZone = ZONE_GMT;
        }

        Calendar calendar = Calendar.getInstance();
        calendar.setTimeZone(TimeZone.getTimeZone(timeZone));
        calendar.setTimeInMillis(timeStamp);
        calendar.setFirstDayOfWeek(2);
        calendar.set(7, calendar.getActualMaximum(7) + 1);
        calendar.set(11, 23);
        calendar.set(12, 59);
        calendar.set(13, 59);
        calendar.set(14, 0);
        return calendar.getTimeInMillis();
    }

    public static Long getLastWeekStartTime(Long timeStamp, String timeZone) {
        if (timeZone == null) {
            timeZone = ZONE_GMT;
        }

        Calendar calendar = Calendar.getInstance();
        calendar.setTimeZone(TimeZone.getTimeZone(timeZone));
        calendar.setTimeInMillis(timeStamp);
        calendar.setFirstDayOfWeek(2);
        calendar.set(7, calendar.getFirstDayOfWeek());
        calendar.set(11, 0);
        calendar.set(13, 0);
        calendar.set(12, 0);
        calendar.set(14, 0);
        calendar.add(5, -7);
        return calendar.getTimeInMillis();
    }

    public static Long getLastWeekEndTime(Long timeStamp, String timeZone) {
        if (timeZone == null) {
            timeZone = ZONE_GMT;
        }

        Calendar calendar = Calendar.getInstance();
        calendar.setTimeZone(TimeZone.getTimeZone(timeZone));
        calendar.setTimeInMillis(timeStamp);
        calendar.setFirstDayOfWeek(2);
        calendar.set(7, calendar.getActualMaximum(7) + 1);
        calendar.set(11, 23);
        calendar.set(12, 59);
        calendar.set(13, 59);
        calendar.set(14, 0);
        calendar.add(5, -7);
        return calendar.getTimeInMillis();
    }

    public static Long getMonthStartTime(Long timeStamp, String timeZone) {
        if (timeZone == null) {
            timeZone = ZONE_GMT;
        }

        Calendar calendar = Calendar.getInstance();
        calendar.setTimeZone(TimeZone.getTimeZone(timeZone));
        calendar.setTimeInMillis(timeStamp);
        calendar.add(1, 0);
        calendar.add(2, 0);
        calendar.set(5, 1);
        calendar.set(11, 0);
        calendar.set(12, 0);
        calendar.set(13, 0);
        calendar.set(14, 0);
        return calendar.getTimeInMillis();
    }

    public static Long getMonthEndTime(Long timeStamp, String timeZone) {
        if (timeZone == null) {
            timeZone = ZONE_GMT;
        }

        Calendar calendar = Calendar.getInstance();
        calendar.setTimeZone(TimeZone.getTimeZone(timeZone));
        calendar.setTimeInMillis(timeStamp);
        calendar.add(1, 0);
        calendar.add(2, 0);
        calendar.set(5, calendar.getActualMaximum(5));
        calendar.set(11, 23);
        calendar.set(12, 59);
        calendar.set(13, 59);
        calendar.set(14, 0);
        return calendar.getTimeInMillis();
    }

    public static Long getLastMonthStartTime(Long timeStamp, String timeZone) {
        if (timeZone == null) {
            timeZone = ZONE_GMT;
        }

        Calendar calendar = Calendar.getInstance();
        calendar.setTimeZone(TimeZone.getTimeZone(timeZone));
        calendar.setTimeInMillis(timeStamp);
        calendar.add(1, 0);
        calendar.add(2, 0);
        calendar.set(5, 1);
        calendar.set(11, 0);
        calendar.set(12, 0);
        calendar.set(13, 0);
        calendar.set(14, 0);
        calendar.add(2, -1);
        return calendar.getTimeInMillis();
    }

    public static Long getLastMonthEndTime(Long timeStamp, String timeZone) {
        if (timeZone == null) {
            timeZone = ZONE_GMT;
        }

        Calendar calendar = Calendar.getInstance();
        calendar.setTimeZone(TimeZone.getTimeZone(timeZone));
        calendar.setTimeInMillis(timeStamp);
        calendar.add(1, 0);
        calendar.add(2, 0);
        calendar.set(5, calendar.getActualMaximum(5));
        calendar.set(11, 23);
        calendar.set(12, 59);
        calendar.set(13, 59);
        calendar.set(14, 0);
        calendar.add(2, -1);
        return calendar.getTimeInMillis();
    }

    public static Long getYearStartTime(Long timeStamp, String timeZone) {
        if (timeZone == null) {
            timeZone = ZONE_GMT;
        }

        Calendar calendar = Calendar.getInstance();
        calendar.setTimeZone(TimeZone.getTimeZone(timeZone));
        calendar.setTimeInMillis(timeStamp);
        calendar.add(1, 0);
        calendar.add(5, 0);
        calendar.add(2, 0);
        calendar.set(6, 1);
        calendar.set(11, 0);
        calendar.set(12, 0);
        calendar.set(13, 0);
        calendar.set(14, 0);
        return calendar.getTimeInMillis();
    }

    public static Long getYearEndTime(Long timeStamp, String timeZone) {
        if (timeZone == null) {
            timeZone = ZONE_GMT;
        }

        Calendar calendar = Calendar.getInstance();
        calendar.setTimeZone(TimeZone.getTimeZone(timeZone));
        calendar.setTimeInMillis(timeStamp);
        int year = calendar.get(1);
        calendar.clear();
        calendar.set(1, year);
        calendar.set(11, 23);
        calendar.set(12, 59);
        calendar.set(13, 59);
        calendar.set(14, 0);
        calendar.roll(6, -1);
        return calendar.getTimeInMillis();
    }

    public static Long getLastYearStartTime(Long timeStamp, String timeZone) {
        if (timeZone == null) {
            timeZone = ZONE_GMT;
        }

        Calendar calendar = Calendar.getInstance();
        calendar.setTimeZone(TimeZone.getTimeZone(timeZone));
        calendar.setTimeInMillis(timeStamp);
        calendar.add(1, -1);
        calendar.add(5, 0);
        calendar.add(2, 0);
        calendar.set(6, 1);
        calendar.set(11, 0);
        calendar.set(12, 0);
        calendar.set(13, 0);
        calendar.set(14, 0);
        return calendar.getTimeInMillis();
    }

    public static Long getLastYearEndTime(Long timeStamp, String timeZone) {
        if (timeZone == null) {
            timeZone = ZONE_GMT;
        }

        Calendar calendar = Calendar.getInstance();
        calendar.setTimeZone(TimeZone.getTimeZone(timeZone));
        calendar.setTimeInMillis(timeStamp);
        int year = calendar.get(1);
        calendar.clear();
        calendar.set(1, year - 1);
        calendar.set(11, 23);
        calendar.set(12, 59);
        calendar.set(13, 59);
        calendar.set(14, 0);
        calendar.roll(6, -1);
        return calendar.getTimeInMillis();
    }

    public static String timestampToStr(long timestamp, String zoneId) {
        if (zoneId == null) {
            zoneId = ZONE_GMT;
        }

        ZoneId timezone = ZoneId.of(zoneId);
        LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), timezone);
        return localDateTime.toString();
    }

    public static List<Date> getDates(Date dBegin, Date dEnd) {
        List lDate = new ArrayList();
        lDate.add(dBegin);
        Calendar calBegin = Calendar.getInstance();
        calBegin.setTime(dBegin);
        Calendar calEnd = Calendar.getInstance();
        calEnd.setTime(dEnd);

        while(dEnd.after(calBegin.getTime())) {
            calBegin.add(5, 1);
            if (dEnd.after(calBegin.getTime())) {
                lDate.add(calBegin.getTime());
            }
        }

        return lDate;
    }

    public static List<Date> getMonths(Date dBegin, Date dEnd) {
        List lDate = new ArrayList();
        lDate.add(dBegin);
        Calendar calBegin = Calendar.getInstance();
        calBegin.setTime(dBegin);
        Calendar calEnd = Calendar.getInstance();
        calEnd.setTime(dEnd);

        while(dEnd.after(calBegin.getTime())) {
            calBegin.add(2, 1);
            if (dEnd.after(calBegin.getTime())) {
                lDate.add(calBegin.getTime());
            }
        }

        return lDate;
    }

    public static Long getPreviousDay(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(5, -1);
        return cal.getTimeInMillis();
    }

    public static void main(String[] args) {
        Date now = new Date();
        Long currentTime = now.getTime();
        System.out.println("Current Time : " + currentTime + " = " + timestampToStr(currentTime, "GMT+8"));
        Long dailyStart = getDailyStartTime(currentTime, "GMT+8:00");
        Long dailyEnd = getDailyEndTime(currentTime, "GMT+8:00");
        Long monthStart = getMonthStartTime(currentTime, "GMT+8:00");
        Long monthEnd = getMonthEndTime(currentTime, "GMT+8:00");
        Long lastMonthStart = getLastMonthStartTime(currentTime, "GMT+8:00");
        Long lastMonthEnd = getLastMonthEndTime(currentTime, "GMT+8:00");
        Long yearStart = getYearStartTime(currentTime, "GMT+8:00");
        Long yearEnd = getYearEndTime(currentTime, "GMT+8:00");
        Long weekStart = getWeekStartTime(currentTime, ZONE_GMT);
        Long weekEnd = getWeekEndTime(currentTime, ZONE_GMT);
        Long lastWeekStart = getLastWeekStartTime(currentTime, ZONE_GMT);
        Long lastWeekEnd = getLastWeekEndTime(currentTime, ZONE_GMT);
        List<Date> dates = getDates(new Date(weekStart), new Date(weekEnd));
        System.out.println("Daily Start : " + dailyStart + " = " + timestampToStr(dailyStart, "GMT+8") + " Daily End : " + dailyEnd + " = " + timestampToStr(dailyEnd, "GMT+8"));
        System.out.println("Month Start : " + monthStart + " = " + timestampToStr(monthStart, "GMT+8") + " Month End : " + monthEnd + " = " + timestampToStr(monthEnd, "GMT+8"));
        System.out.println("Last Month Start : " + lastMonthStart + " = " + timestampToStr(lastMonthStart, "GMT+8") + " Last Month End : " + lastMonthEnd + " = " + timestampToStr(lastMonthEnd, "GMT+8"));
        System.out.println("Year Start : " + yearStart + " = " + timestampToStr(yearStart, "GMT+8") + " Year End : " + yearEnd + " = " + timestampToStr(yearEnd, "GMT+8"));
        System.out.println("Week Start : " + weekStart + " = " + timestampToStr(weekStart, "GMT+8") + " Week End : " + weekEnd + " = " + timestampToStr(weekEnd, "GMT+8"));
        System.out.println("Last Week Start : " + lastWeekStart + " = " + timestampToStr(lastWeekStart, "GMT+8") + " Last Week End : " + lastWeekEnd + " = " + timestampToStr(lastWeekEnd, "GMT+8"));
        System.out.println(dates);
        System.out.println(thisday());
    }

    public static class Thisday {
        private Integer year;
        private Integer month;
        private Integer day;
        private Integer quarter;

        public Thisday() {
        }

        public Integer getYear() {
            return this.year;
        }

        public void setYear(Integer year) {
            this.year = year;
        }

        public Integer getMonth() {
            return this.month;
        }

        public void setMonth(Integer month) {
            this.month = month;
        }

        public Integer getDay() {
            return this.day;
        }

        public void setDay(Integer day) {
            this.day = day;
        }

        public Integer getQuarter() {
            return this.quarter;
        }

        public void setQuarter(Integer quarter) {
            this.quarter = quarter;
        }

        public String toString() {
            return "Thisday{year=" + this.year + ", month=" + this.month + ", day=" + this.day + ", quarter=" + this.quarter + '}';
        }
    }
}
